home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 25 / CU Amiga Magazine's Super CD-ROM 25 (1998)(EMAP Images)(GB)(Track 1 of 2)[!][issue 1998-08].iso / CUCD / Programming / QuakeTools / src / libqbuild / light.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-06-11  |  20.9 KB  |  845 lines

  1. #define    LIBQBUILD_CORE
  2. #include "../include/libqbuild.h"
  3.  
  4. int c_bad;
  5. struct tnode *tnodes, *tnode_p;
  6. bool *nolightface;
  7. float *minlights;
  8. float rangescale = 0.5;
  9. float scalecos = 0.5;
  10. float scaledist = 1.0;
  11. int bspfileface;                        // next surface to dispatch
  12. vec3_t *faceoffset;
  13. vec3_t bsp_origin;
  14.  
  15. /*
  16.  * ==============================================================================
  17.  * 
  18.  * LINE TRACING
  19.  * 
  20.  * The major lighting operation is a point to point visibility test, performed
  21.  * by recursive subdivision of the line by the BSP tree.
  22.  * 
  23.  * ==============================================================================
  24.  */
  25.  
  26. bool TestLine(vec3_t start, vec3_t stop)
  27. {
  28.   int node;
  29.   float front, back;
  30.   tracestack_t *tstack_p;
  31.   int side;
  32.   float frontx, fronty, frontz, backx, backy, backz;
  33.   tracestack_t tracestack[64];
  34.   struct tnode *tnode;
  35.  
  36.   frontx = start[0];
  37.   fronty = start[1];
  38.   frontz = start[2];
  39.   backx = stop[0];
  40.   backy = stop[1];
  41.   backz = stop[2];
  42.  
  43.   tstack_p = tracestack;
  44.   node = 0;
  45.  
  46.   while (1) {
  47.     while (node < 0 && node != CONTENTS_SOLID) {
  48.       // pop up the stack for a back side
  49.       tstack_p--;
  50.       if (tstack_p < tracestack)
  51.     return TRUE;
  52.       node = tstack_p->node;
  53.  
  54.       // set the hit point for this plane
  55.  
  56.       frontx = backx;
  57.       fronty = backy;
  58.       frontz = backz;
  59.  
  60.       // go down the back side
  61.  
  62.       backx = tstack_p->backpt[0];
  63.       backy = tstack_p->backpt[1];
  64.       backz = tstack_p->backpt[2];
  65.  
  66.       node = tnodes[tstack_p->node].children[!tstack_p->side];
  67.     }
  68.  
  69.     if (node == CONTENTS_SOLID)
  70.       return FALSE;                                   // DONE!
  71.  
  72.     tnode = &tnodes[node];
  73.  
  74.     switch (tnode->type) {
  75.       case PLANE_X:
  76.     front = frontx - tnode->dist;
  77.     back = backx - tnode->dist;
  78.     break;
  79.       case PLANE_Y:
  80.     front = fronty - tnode->dist;
  81.     back = backy - tnode->dist;
  82.     break;
  83.       case PLANE_Z:
  84.     front = frontz - tnode->dist;
  85.     back = backz - tnode->dist;
  86.     break;
  87.       default:
  88.     front = (frontx * tnode->normal[0] + fronty * tnode->normal[1] + frontz * tnode->normal[2]) - tnode->dist;
  89.     back = (backx * tnode->normal[0] + backy * tnode->normal[1] + backz * tnode->normal[2]) - tnode->dist;
  90.     break;
  91.     }
  92.  
  93.     if (front > -ON_EPSILON && back > -ON_EPSILON)
  94. //              if (front > 0 && back > 0)
  95.     {
  96.       node = tnode->children[0];
  97.       continue;
  98.     }
  99.  
  100.     if (front < ON_EPSILON && back < ON_EPSILON)
  101. //              if (front <= 0 && back <= 0)
  102.     {
  103.       node = tnode->children[1];
  104.       continue;
  105.     }
  106.  
  107.     side = front < 0;
  108.  
  109.     front = front / (front - back);
  110.  
  111.     tstack_p->node = node;
  112.     tstack_p->side = side;
  113.     tstack_p->backpt[0] = backx;
  114.     tstack_p->backpt[1] = backy;
  115.     tstack_p->backpt[2] = backz;
  116.  
  117.     tstack_p++;
  118.  
  119.     backx = frontx + front * (backx - frontx);
  120.     backy = fronty + front * (backy - fronty);
  121.     backz = frontz + front * (backz - frontz);
  122.  
  123.     node = tnode->children[side];
  124.   }
  125. }
  126.  
  127. /*
  128.  * ============
  129.  * CastRay
  130.  * 
  131.  * Returns the distance between the points, or -1 if blocked
  132.  * =============
  133.  */
  134. vec_t CastRay(register vec3_t p1, register vec3_t p2)
  135. {
  136.   short int i;
  137.   vec_t t;
  138.  
  139.   if(!TestLine(p1, p2))
  140.     return -1;                                       // ray was blocked
  141.  
  142.   t = 0;
  143.   for (i = 0; i < 3; i++)
  144.     t += (p2[i] - p1[i]) * (p2[i] - p1[i]);
  145.  
  146.   if (t == 0)
  147.     t = 1;                                       // don't blow up...
  148.  
  149.   return sqrt(t);
  150. }
  151.  
  152. /*
  153.  * ===================================================================
  154.  * 
  155.  * TRANSFER SCALES
  156.  * 
  157.  * ===================================================================
  158.  */
  159.  
  160. /*
  161.  * ==============
  162.  * MakeTnode
  163.  * 
  164.  * Converts the disk node structure into the efficient tracing structure
  165.  * ==============
  166.  */
  167. void MakeTnode(__memBase, register int nodenum)
  168. {
  169.   struct tnode *t;
  170.   struct dplane_t *plane;
  171.   short int i;
  172.   struct dnode_t *node;
  173.  
  174.   t = tnode_p++;
  175.  
  176.   node = bspMem->dnodes + nodenum;
  177.   plane = bspMem->dplanes + node->planenum;
  178.  
  179.   t->type = plane->type;
  180.   VectorCopy(plane->normal, t->normal);
  181.   t->dist = plane->dist;
  182.  
  183.   for (i = 0; i < 2; i++) {
  184.     if (node->children[i] < 0)
  185.       t->children[i] = bspMem->dleafs[-node->children[i] - 1].contents;
  186.     else {
  187.       t->children[i] = tnode_p - tnodes;
  188.       MakeTnode(bspMem, node->children[i]);
  189.     }
  190.   }
  191.  
  192. }
  193.  
  194. /*
  195.  * =============
  196.  * MakeTnodes
  197.  * 
  198.  * Loads the node structure out of a .bsp file to be used for light occlusion
  199.  * =============
  200.  */
  201. void MakeTnodes(__memBase, register struct dmodel_t * bm)
  202. {
  203.   if(!(tnode_p = tnodes = (struct tnode *)kmalloc(bspMem->numnodes * sizeof(struct tnode))))
  204.     Error("MakeTnodes: failed to allocate tnode!\n");
  205.   MakeTnode(bspMem, 0);
  206. }
  207.  
  208. /*
  209.  * ===============================================================================
  210.  * 
  211.  * SAMPLE POINT DETERMINATION
  212.  * 
  213.  * void SetupBlock (dface_t *f) Returns with surfpt[] set
  214.  * 
  215.  * This is a little tricky because the lightmap covers more area than the face.
  216.  * If done in the straightforward fashion, some of the
  217.  * sample points will be inside walls or on the other side of walls, causing
  218.  * FALSE shadows and light bleeds.
  219.  * 
  220.  * To solve this, I only consider a sample point valid if a line can be drawn
  221.  * between it and the exact midpoint of the face.  If invalid, it is adjusted
  222.  * towards the center until it is valid.
  223.  * 
  224.  * (this doesn't completely work)
  225.  * 
  226.  * ===============================================================================
  227.  */
  228.  
  229. /*
  230.  * ================
  231.  * CalcFaceVectors
  232.  * 
  233.  * Fills in texorg, worldtotex. and textoworld
  234.  * ================
  235.  */
  236. void CalcFaceVectors(__memBase, register struct lightinfo *l)
  237. {
  238.   struct texinfo *tex;
  239.   short int i, j;
  240.   vec3_t texnormal;
  241.   float distscale;
  242.   vec_t dist, len;
  243.  
  244.   tex = &bspMem->texinfo[l->face->texinfo];
  245.  
  246. // convert from float to vec_t
  247.   for (i = 0; i < 2; i++)
  248.     for (j = 0; j < 3; j++)
  249.       l->worldtotex[i][j] = tex->vecs[i][j];
  250.  
  251. // calculate a normal to the texture axis.  points can be moved along this
  252.   // without changing their S/T
  253.   texnormal[0] = tex->vecs[1][1] * tex->vecs[0][2] - tex->vecs[1][2] * tex->vecs[0][1];
  254.   texnormal[1] = tex->vecs[1][2] * tex->vecs[0][0] - tex->vecs[1][0] * tex->vecs[0][2];
  255.   texnormal[2] = tex->vecs[1][0] * tex->vecs[0][1] - tex->vecs[1][1] * tex->vecs[0][0];
  256.   VectorNormalize(texnormal);
  257.  
  258. // flip it towards plane normal
  259.   distscale = DotProduct(texnormal, l->facenormal);
  260.   if (!distscale)
  261.     Error("Texture axis perpendicular to face\n"
  262.       "Face point at ( %g %g %g )\n",
  263.       bspMem->dvertexes[bspMem->dedges[l->face->firstedge].v[0]].point[0],
  264.       bspMem->dvertexes[bspMem->dedges[l->face->firstedge].v[0]].point[1],
  265.       bspMem->dvertexes[bspMem->dedges[l->face->firstedge].v[0]].point[2]);
  266.   if (distscale < 0) {
  267.     distscale = -distscale;
  268.     VectorNegate(texnormal);
  269.   }
  270.  
  271. // distscale is the ratio of the distance along the texture normal to
  272.   // the distance along the plane normal
  273.   distscale = 1 / distscale;
  274.  
  275.   for (i = 0; i < 2; i++) {
  276.     len = VectorLength(l->worldtotex[i]);
  277.     dist = DotProduct(l->worldtotex[i], l->facenormal);
  278.     dist *= distscale;
  279.     VectorMA(l->worldtotex[i], -dist, texnormal, l->textoworld[i]);
  280.     VectorScale(l->textoworld[i], (1 / len) * (1 / len), l->textoworld[i]);
  281.   }
  282.  
  283. //JIM
  284.   // calculate texorg on the texture plane
  285.   for (i = 0; i < 3; i++)
  286.     l->texorg[i] = -tex->vecs[0][3] * l->textoworld[0][i] - tex->vecs[1][3] * l->textoworld[1][i];
  287.  
  288. // project back to the face plane
  289.   dist = DotProduct(l->texorg, l->facenormal) - l->facedist - 1;
  290.   dist *= distscale;
  291.   VectorMA(l->texorg, -dist, texnormal, l->texorg);
  292.  
  293. }
  294.  
  295. /*
  296.  * ================
  297.  * CalcFaceExtents
  298.  * 
  299.  * Fills in s->texmins[] and s->texsize[]
  300.  * also sets exactmins[] and exactmaxs[]
  301.  * ================
  302.  */
  303. void CalcFaceExtents(__memBase, register struct lightinfo *l, register vec3_t faceoffset)
  304. {
  305.   struct dface_t *s;
  306.   vec_t mins[2], maxs[2], val;
  307.   int i, e;
  308.   short int j;
  309.   struct dvertex_t *v;
  310.   struct texinfo *tex;
  311.  
  312.   s = l->face;
  313.  
  314.   mins[0] = mins[1] = 999999;
  315.   maxs[0] = maxs[1] = -99999;
  316.  
  317.   tex = &bspMem->texinfo[s->texinfo];
  318.  
  319.   for (i = 0; i < s->numedges; i++) {
  320.     e = bspMem->dsurfedges[s->firstedge + i];
  321.     if (e >= 0)
  322.       v = bspMem->dvertexes + bspMem->dedges[e].v[0];
  323.     else
  324.       v = bspMem->dvertexes + bspMem->dedges[-e].v[1];
  325.  
  326.     for (j = 0; j < 2; j++) {
  327.       val = (v->point[0] + faceoffset[0]) * tex->vecs[j][0] +
  328.     (v->point[1] + faceoffset[1]) * tex->vecs[j][1] +
  329.     (v->point[2] + faceoffset[2]) * tex->vecs[j][2] +
  330.     tex->vecs[j][3];
  331.       if (val < mins[j])
  332.     mins[j] = val;
  333.       if (val > maxs[j])
  334.     maxs[j] = val;
  335.     }
  336.   }
  337.  
  338.   for (i = 0; i < 2; i++) {
  339.     l->exactmins[i] = mins[i];
  340.     l->exactmaxs[i] = maxs[i];
  341.  
  342.     mins[i] = floor(mins[i] / 16);
  343.     maxs[i] = ceil(maxs[i] / 16);
  344.  
  345.     l->texmins[i] = mins[i];
  346.     l->texsize[i] = maxs[i] - mins[i];
  347.     if (l->texsize[i] > 17)
  348.       Error("Bad surface extents\n");
  349.   }
  350. }
  351.  
  352. /*
  353.  * =================
  354.  * CalcPoints
  355.  * 
  356.  * For each texture aligned grid point, back project onto the plane
  357.  * to get the world xyz value of the sample point
  358.  * =================
  359.  */
  360. void CalcPoints(__memBase, struct lightinfo *l, register float sofs, register float tofs)
  361. {
  362.   int s, t;
  363.   short int i, j;
  364.   int w, h, step;
  365.   vec_t starts, startt, us, ut;
  366.   vec_t *surf;
  367.   vec_t mids, midt;
  368.   vec3_t facemid, move;
  369.  
  370. //
  371.   // fill in surforg
  372.   // the points are biased towards the center of the surface
  373.   // to help avoid edge cases just inside walls
  374.   //
  375.   surf = l->surfpt[0];
  376.   mids = (l->exactmaxs[0] + l->exactmins[0]) / 2;
  377.   midt = (l->exactmaxs[1] + l->exactmins[1]) / 2;
  378.  
  379.   for (j = 0; j < 3; j++)
  380.     facemid[j] = l->texorg[j] + l->textoworld[0][j] * mids + l->textoworld[1][j] * midt;
  381.  
  382.   if ((bspMem->litOptions & LIGHT_EXTRA) && !(bspMem->litOptions & LIGHT_RADIOSITY)) {           // extra filtering
  383.     h = (l->texsize[1] + 1) * 2;
  384.     w = (l->texsize[0] + 1) * 2;
  385.     starts = (l->texmins[0] - 0.5) * 16;
  386.     startt = (l->texmins[1] - 0.5) * 16;
  387.     step = 8;
  388.   }
  389.   else {
  390.     h = l->texsize[1] + 1;
  391.     w = l->texsize[0] + 1;
  392.     starts = l->texmins[0] * 16;
  393.     startt = l->texmins[1] * 16;
  394.     step = 16;
  395.   }
  396.  
  397.   l->numsurfpt = w * h;
  398.   for (t = 0; t < h; t++) {
  399.     for (s = 0; s < w; s++, surf += 3) {
  400.       us = starts + ((s + sofs) * step);
  401.       ut = startt + ((t + tofs) * step);
  402.  
  403.       // if a line can be traced from surf to facemid, the point is good
  404.       for (i = 0; i < 6; i++) {
  405.     // calculate texture point
  406.     //JIM
  407.     for (j = 0; j < 3; j++)
  408.       surf[j] = l->texorg[j] + l->textoworld[0][j] * us + l->textoworld[1][j] * ut;
  409.  
  410.     if (TestLine(facemid, surf))
  411.       break;                                   // got it
  412.  
  413.     if (i & 1) {
  414.       if (us > mids) {
  415.         us -= 8;
  416.         if (us < mids)
  417.           us = mids;
  418.       }
  419.       else {
  420.         us += 8;
  421.         if (us > mids)
  422.           us = mids;
  423.       }
  424.     }
  425.     else {
  426.       if (ut > midt) {
  427.         ut -= 8;
  428.         if (ut < midt)
  429.           ut = midt;
  430.       }
  431.       else {
  432.         ut += 8;
  433.         if (ut > midt)
  434.           ut = midt;
  435.       }
  436.     }
  437.  
  438.     // move surf 8 pixels towards the center
  439.     VectorSubtract(facemid, surf, move);
  440.     VectorNormalize(move);
  441.     VectorMA(surf, 8, move, surf);
  442.       }
  443.       if (i == 2)
  444.     c_bad++;
  445.     }
  446.   }
  447.  
  448. }
  449.  
  450. /*
  451.  * ===============================================================================
  452.  * 
  453.  * FACE LIGHTING
  454.  * 
  455.  * ===============================================================================
  456.  */
  457.  
  458. int c_culldistplane, c_proper;
  459.  
  460. /*
  461.  * ================
  462.  * SingleLightFace
  463.  * ================
  464.  */
  465. void SingleLightFace(register struct entity *light, register struct lightinfo * l, register vec3_t faceoffset)
  466. {
  467.   vec_t dist;
  468.   vec3_t incoming;
  469.   vec_t angle;
  470.   vec_t add;
  471.   vec_t *surf;
  472.   bool hit;
  473.   int mapnum;
  474.   int size;
  475.   int c, i;
  476.   vec3_t rel;
  477.   vec3_t spotvec;
  478.   vec_t falloff;
  479.   vec_t *lightsamp;
  480.  
  481.   VectorSubtract(light->origin, bsp_origin, rel);
  482.   //VectorSubtract (rel, faceoffset, rel);
  483.   dist = scaledist * (DotProduct(rel, l->facenormal) - l->facedist);
  484.  
  485. // don't bother with lights behind the surface
  486.   if (dist <= 0)
  487.     return;
  488.  
  489. // don't bother with light too far away
  490.   if (dist > light->light) {
  491.     c_culldistplane++;
  492.     return;
  493.   }
  494.  
  495.   if (light->targetent) {
  496.     VectorSubtract(light->targetent->origin, light->origin, spotvec);
  497.     VectorNormalize(spotvec);
  498.     if (!light->angle)
  499.       falloff = -cos(20 * Q_PI / 180);
  500.     else
  501.       falloff = -cos(light->angle / 2 * Q_PI / 180);
  502.   }
  503.   else
  504.     falloff = 0;                                   // shut up compiler warnings
  505.  
  506.   mapnum = 0;
  507.   for (mapnum = 0; mapnum < l->numlightstyles; mapnum++)
  508.     if (l->lightstyles[mapnum] == light->style)
  509.       break;
  510.   lightsamp = l->lightmaps[mapnum];
  511.   if (mapnum == l->numlightstyles) {                           // init a new light map
  512.     if (mapnum >= MAXLIGHTMAPS) {
  513.       eprintf("Too many light styles on a face\n");
  514.       return;
  515.     }
  516.     size = (l->texsize[1] + 1) * (l->texsize[0] + 1);
  517.     for (i = 0; i < size; i++)
  518.       lightsamp[i] = 0;
  519.   }
  520.  
  521. //
  522.   // check it for real
  523.   //
  524.   hit = FALSE;
  525.   c_proper++;
  526.  
  527.   surf = l->surfpt[0];
  528.   for (c = 0; c < l->numsurfpt; c++, surf += 3) {
  529.     if((dist = CastRay(light->origin, surf) * scaledist) < 0)
  530.       continue;                                       // light doesn't reach
  531.  
  532.     VectorSubtract(light->origin, surf, incoming);
  533.     VectorNormalize(incoming);
  534.     angle = DotProduct(incoming, l->facenormal);
  535.     if (light->targetent) {                               // spotlight cutoff
  536.       if (DotProduct(spotvec, incoming) > falloff)
  537.     continue;
  538.     }
  539.  
  540.     angle = (1.0 - scalecos) + scalecos * angle;
  541.     add = light->light - dist;
  542.     add *= angle;
  543.     if (add < 0)
  544.       continue;
  545.     lightsamp[c] += add;
  546.     if (lightsamp[c] > 1)                               // ignore real tiny lights
  547.       hit = TRUE;
  548.   }
  549.  
  550.   if (mapnum == l->numlightstyles && hit) {
  551.     l->lightstyles[mapnum] = light->style;
  552.     l->numlightstyles++;                               // the style has some real data now
  553.   }
  554. }
  555.  
  556. /*
  557.  * ============
  558.  * FixMinlight
  559.  * ============
  560.  */
  561. void FixMinlight(register struct lightinfo *l)
  562. {
  563.   int i, j;
  564.   float minlight;
  565.  
  566.   minlight = minlights[l->surfnum];
  567.  
  568. // if minlight is set, there must be a style 0 light map
  569.   if (!minlight)
  570.     return;
  571.  
  572.   for (i = 0; i < l->numlightstyles; i++) {
  573.     if (l->lightstyles[i] == 0)
  574.       break;
  575.   }
  576.   if (i == l->numlightstyles) {
  577.     if (l->numlightstyles >= MAXLIGHTMAPS)
  578.       return;                                       // oh well..
  579.  
  580.     for (j = 0; j < l->numsurfpt; j++)
  581.       l->lightmaps[i][j] = minlight;
  582.     l->lightstyles[i] = 0;
  583.     l->numlightstyles++;
  584.   }
  585.   else {
  586.     for (j = 0; j < l->numsurfpt; j++)
  587.       if (l->lightmaps[i][j] < minlight)
  588.     l->lightmaps[i][j] = minlight;
  589.   }
  590. }
  591.  
  592. unsigned char *GetFileSpace(__memBase, register int size)
  593. {
  594.   unsigned char *ret;
  595.  
  596.   size = ((size + 3) & ~3);
  597.   if(bspMem->lightdatasize + size >= bspMem->max_lightdatasize)
  598.     ExpandClusters(bspMem, LUMP_LIGHTING);
  599.   ret = bspMem->dlightdata + bspMem->lightdatasize;
  600.   bspMem->lightdatasize += size;
  601.  
  602.   return ret;
  603. }
  604.  
  605. /*
  606.  * ============
  607.  * LightFace
  608.  * ============
  609.  */
  610. void LightFace(__memBase, register int facenum, register bool nolight, register vec3_t faceoffset)
  611. {
  612.   struct dface_t *f;
  613.   struct lightinfo l;
  614.   int s, t;
  615.   short int i, j, c;
  616.   vec_t total;
  617.   int size;
  618.   int lightmapwidth, lightmapsize;
  619.   unsigned char *out;
  620.   vec_t *light;
  621.   int w, h;
  622.   vec3_t point;
  623.  
  624.   f = bspMem->dfaces + facenum;
  625.  
  626. //
  627.   // some surfaces don't need lightmaps
  628.   //
  629.   f->lightofs = -1;
  630.   for (j = 0; j < MAXLIGHTMAPS; j++)
  631.     f->styles[j] = 255;
  632.  
  633. /** added waterlit **/
  634.   if ((bspMem->texinfo[f->texinfo].flags & TEX_SPECIAL)) {               // non-lit texture
  635.     if(bspMem->litOptions & LIGHT_WATERLIT) {
  636.       int *textures = (int *)(bspMem->dtexdata + 4);
  637.       struct mipmap *tex = (struct mipmap *)(bspMem->dtexdata + textures[bspMem->texinfo[f->texinfo].miptex]);
  638.       if(!strcmp(tex->name, "sky"))
  639.         return;
  640.     }
  641.     else
  642.       return;
  643.   }
  644.   memset(&l, 0, sizeof(l));
  645.   l.surfnum = facenum;
  646.   l.face = f;
  647.  
  648. //
  649.   // rotate plane
  650.   //
  651.   VectorCopy(bspMem->dplanes[f->planenum].normal, l.facenormal);
  652.   l.facedist = bspMem->dplanes[f->planenum].dist;
  653.   VectorScale(l.facenormal, l.facedist, point);
  654.   VectorAdd(point, faceoffset, point);
  655.   l.facedist = DotProduct(point, l.facenormal);
  656.  
  657.   if (f->side) {
  658.     VectorNegate(l.facenormal);
  659.     l.facedist = -l.facedist;
  660.   }
  661.  
  662.   CalcFaceVectors(bspMem, &l);
  663.   CalcFaceExtents(bspMem, &l, faceoffset);
  664.   CalcPoints(bspMem, &l, 0, 0);
  665.  
  666.   lightmapwidth = l.texsize[0] + 1;
  667.   size = lightmapwidth * (l.texsize[1] + 1);
  668.   if (size > SINGLEMAP)
  669.     Error("Bad lightmap size");
  670.  
  671.   for (i = 0; i < MAXLIGHTMAPS; i++)
  672.     l.lightstyles[i] = 255;
  673.  
  674. //
  675.   // cast all lights
  676.   //
  677.  /*
  678.   if (nolight == TRUE) {
  679.     float value;
  680.    
  681.     l.numlightstyles = 1;
  682.     l.lightstyles[0] = 0;
  683.     value = nolight + 40 * l.facenormal[ 0 ] - 50 * l.facenormal[ 1 ] +
  684.     60 * l.facenormal[ 2 ];
  685.     for (i=0 ; i<l.numsurfpt ; i++)
  686.       l.lightmaps[0][i] = value;
  687.   }
  688.   else {
  689.   */
  690.     l.numlightstyles = 0;
  691.     for (i = 0; i < bspMem->nummapentities; i++) {
  692.       if (bspMem->mapentities[i].light)
  693.         SingleLightFace(&bspMem->mapentities[i], &l, faceoffset);
  694.     }
  695.     FixMinlight(&l);
  696.     if (!l.numlightstyles)                               // no light hitting it
  697.       return;
  698.  /*
  699.   }
  700.   */
  701.  
  702. //
  703.   // save out the values
  704.   //
  705.   for (i = 0; i < MAXLIGHTMAPS; i++)
  706.     f->styles[i] = l.lightstyles[i];
  707.  
  708.   lightmapsize = size * l.numlightstyles;
  709.   f->lightofs = bspMem->lightdatasize;
  710.   out = GetFileSpace(bspMem, lightmapsize);
  711.  
  712. // extra filtering
  713.   h = (l.texsize[1] + 1) * 2;
  714.   w = (l.texsize[0] + 1) * 2;
  715.  
  716.   for (i = 0; i < l.numlightstyles; i++) {
  717.     if (l.lightstyles[i] == 0xff)
  718.       Error("Wrote empty lightmap");
  719.     light = l.lightmaps[i];
  720.     c = 0;
  721.     for (t = 0; t <= l.texsize[1]; t++)
  722.       for (s = 0; s <= l.texsize[0]; s++, c++) {
  723.     if (bspMem->litOptions & LIGHT_EXTRA) {                               // filtered sample
  724.       total = light[ t * 2      * w + s * 2    ] +
  725.               light[ t * 2      * w + s * 2 + 1] +
  726.               light[(t * 2 + 1) * w + s * 2    ] +
  727.               light[(t * 2 + 1) * w + s * 2 + 1];
  728.       total *= 0.25;
  729.     }
  730.     else
  731.       total = light[c];
  732.     total *= rangescale;                               // scale before clamping
  733.  
  734.     if (total > 255)
  735.       total = 255;
  736.     if (total < 0)
  737.       Error("light < 0");
  738.     *out++ = total;
  739.       }
  740.   }
  741. }
  742.  
  743. //JIM
  744. void FindFaceOffsets(__memBase)
  745. {
  746.   int i, j;
  747.   struct entity *ent;
  748.   struct dmodel_t *mod;
  749.  
  750.   for (j = bspMem->dmodels[0].firstface; j < bspMem->dmodels[0].numfaces; j++) {
  751.     nolightface[j] = FALSE;
  752.   }
  753.   for (i = 1; i < bspMem->nummodels; i++) {
  754.     mod = &bspMem->dmodels[i];
  755.     ent = FindEntityWithModel(bspMem, i);
  756.  
  757.     if (!strncmp(ent->classname, "rotate_", 7)) {
  758.       int start = mod->firstface;
  759.       int end = start + mod->numfaces;
  760.       for (j = start; j < end; j++) {
  761.     nolightface[j] = 300;
  762.     VectorCopy(ent->origin, faceoffset[j]);
  763.       }
  764.     }
  765.   }
  766. }
  767.  
  768. /*
  769.  * =============
  770.  * LightWorld
  771.  * =============
  772.  */
  773. void LightWorld(__memBase)
  774. {
  775.   int i;
  776.  
  777.   FindFaceOffsets(bspMem);
  778.   for (i = 0; i < bspMem->numfaces; i++, bspfileface++) {
  779.     LightFace(bspMem, i, nolightface[i], faceoffset[i]);
  780.     mprogress(bspMem->numfaces, i + 1);
  781.   }
  782. }
  783.  
  784. bool light(__memBase, float scale, float range)
  785. {
  786.   mprintf("----- LightFaces --------\n");
  787.  
  788.   if(scale)
  789.     scaledist = scale;
  790.   if(range)
  791.     rangescale = range;
  792.     
  793.   AllocClusters(bspMem, LUMP_LIGHTING);
  794.     
  795.   if(!(minlights = (float *)kmalloc(sizeof(float) * bspMem->numfaces)))
  796.     Error("Light: failed to allocate minlights!\n");
  797.   if(!(nolightface = (bool *)kmalloc(sizeof(bool) * bspMem->numfaces)))
  798.     Error("Lights: failed to allocate nolightfaces!\n");
  799.   if(!(faceoffset = (vec3_t *)kmalloc(sizeof(vec3_t) * bspMem->numfaces)))
  800.     Error("Lights: failed to allocate faceoffsets!\n");
  801.  
  802.   if(bspMem->litOptions & LIGHT_RADIOSITY) {
  803.     if(!(facepatches = (struct patch **)kmalloc(sizeof(struct patch *) * bspMem->numfaces)))
  804.       Error("Light: failed to allocate facepatches!\n");
  805.     if(!(faceentity = (struct entity **)kmalloc(sizeof(struct entity *) * bspMem->numfaces)))
  806.       Error("Light: failed to allocate facentities!\n");
  807.     if(!(facelights = (struct facelight *)kmalloc(sizeof(struct entity *) * bspMem->numfaces)))
  808.       Error("Light: failed to allocate facelights!\n");
  809.     if(!(patches = (struct patch *)kmalloc(sizeof(struct patch) * 4096)))
  810.       Error("Light: failed to allocate patches!\n");
  811.     if(!(radiosity = (vec3_t *)kmalloc(sizeof(vec3_t) * bspMem->numfaces)))
  812.       Error("Light: failed to allocate radiosity!\n");
  813.     if(!(illumination = (vec3_t *)kmalloc(sizeof(vec3_t) * bspMem->numfaces)))
  814.       Error("Light: failed to allocate illumination!\n");
  815.     if(!(backplanes = (struct dplane_t *)kmalloc(sizeof(struct dplane_t) * bspMem->numplanes)))
  816.       Error("Light: failed to allocate backplanes!\n");
  817.     if(!(directlights = (struct directlight **)kmalloc(sizeof(struct directlight *) * bspMem->numleafs)))
  818.       Error("Light: failed to allocate directlights!\n");
  819.     if(!(leafparents = (int *)kmalloc(sizeof(int) * bspMem->numleafs)))
  820.       Error("Light: failed to allocate leafparents!\n");
  821.     if(!(nodeparents = (int *)kmalloc(sizeof(int) * bspMem->numnodes)))
  822.       Error("Light: failed to allocate nodeparents!\n");
  823.     if(!(texreflectivity = (vec3_t *)kmalloc(sizeof(vec3_t) * bspMem->numtexinfo)))
  824.       Error("Lights: failed to allocate texture reflectivity!\n");
  825.   }
  826.     
  827.   if(!(bspMem->litOptions & LIGHT_MEM)) {
  828.     bspMem->mapOptions |= MAP_LOADLIGHTS;
  829.     LoadMapFile(bspMem, bspMem->dentdata);
  830.   }
  831.  
  832.   MakeTnodes(bspMem, &bspMem->dmodels[0]);
  833.  
  834.   if(bspMem->litOptions & LIGHT_RADIOSITY)
  835.     RadWorld(bspMem);
  836.   else
  837.     LightWorld(bspMem);
  838.  
  839.   WriteEntitiesToString(bspMem);
  840.   kfree();
  841.  
  842.   return TRUE;
  843. }
  844.  
  845.